Namespace.Use("UI.Object", function(ns) {
    //
    //  Imports.
    //
    var Inherit = Namespace.Import("Base.Inherit");

    //
    //  Global.
    //
    var cst_InitialWidth = 100;
    var cst_InitialHeight = 100;
    var cst_InitialX = 0;
    var cst_InitialY = 0;
    var cst_InitialVisibility = true;
    var cst_InitialLayer = 0;
    var cst_InitialBackgroundColor = "transparent";
    var cst_InitialOverflowX = "hidden";
    var cst_InitialOverflowY = "hidden";

    //
    //  Classes.
    //
    function AbsoluteContainer() {
        //  Let parent class initialize.
        ns.BaseContainer.call(this);

        //
        //  Members.
        //
        var invalidate_children = false;
        var children = [];
        var element = $("<div></div>").css({
            "position": "absolute",
            "border": 0,
            "padding": 0,
            "margin": 0
        });
        var last_width = -1, last_height = -1;
        var width = cst_InitialWidth, height = cst_InitialHeight;
        var last_x = -1, last_y = -1;
        var x = cst_InitialX, y = cst_InitialY;
        var last_visibility = !cst_InitialVisibility;
        var visibility = cst_InitialVisibility;
        var last_layer = -1;
        var layer = cst_InitialLayer;
        var last_bgcolor = null;
        var bgcolor = cst_InitialBackgroundColor;
        var last_overflow_x = null, last_overflow_y = null;
        var overflow_x = cst_InitialOverflowX, overflow_y = cst_InitialOverflowY;

        //
        //  Private methods.
        //
        function GetEventOffsetPosition(event) {
            var offset = element.offset();
            return [
                event.offsetX || event.pageX - offset.left,
                event.offsetY || event.pageY - offset.top
            ];
        }

        //
        //  Public methods.
        //
        this.GetHTMLElement = function() {
            return element[0];
        };
        this.Invalidate = function() {
            //  Update the position.
            if (last_x != x) {
                element.css({
                    "left": x
                });
                last_x = x;
                invalidate_children = true;
            }
            if (last_y != y) {
                element.css({
                    "top": y
                });
                last_y = y;
                invalidate_children = true;
            }

            //  Update the size.
            var size_updated = false;
            if (last_width != width) {
                element.css({
                    "width": width
                });
                last_width = width;
                invalidate_children = true;
                size_updated = true;
            }
            if (last_height != height) {
                element.css({
                    "height": height
                });
                last_height = height;
                invalidate_children = true;
                size_updated = true;
            }
            if (size_updated == true) {
                this.TriggerEvent("Resize", [width, height]);
            }

            //  Update the visibility.
            if (last_visibility != visibility) {
                if (visibility == true) {
                    element.show();
                } else {
                    element.hide();
                }
                last_visibility = visibility;
                invalidate_children = true;
            }

            //  Update the layer.
            if (last_layer != layer) {
                element.css({
                    "z-index": layer
                });
                last_layer = layer;
                invalidate_children = true;
            }

            //  Update the background color.
            if (last_bgcolor != bgcolor) {
                element.css({
                    "background-color": bgcolor
                });
                last_bgcolor = bgcolor;
                invalidate_children = true;
            }

            //  Update the overflow settings.
            if (last_overflow_x != overflow_x) {
                element.css({
                    "overflow-x": overflow_x
                });
                last_overflow_x = overflow_x;
                invalidate_children = true;
            }
            if (last_overflow_y != overflow_y) {
                element.css({
                    "overflow-y": overflow_y
                });
                last_overflow_y = overflow_y;
                invalidate_children = true;
            }

            //  Update the children.
            if (invalidate_children == true) {
                children.forEach(function(child) {
                    child.Invalidate();
                });
                invalidate_children = false;
            }
        };
        this.AccessPosition = Polymorphic.Create(
            [],
            function() {
                return [x, y];
            },
            [Number, Number],
            function(new_x, new_y) {
                last_x = x;
                last_y = y;
                x = new_x;
                y = new_y;
                this.Invalidate();
            }
        );
        this.AccessSize = Polymorphic.Create(
            [],
            function() {
                return [width, height];
            },
            [Number, Number],
            function(new_width, new_height) {
                last_width = width;
                last_height = height;
                width = new_width;
                height = new_height;
                this.Invalidate();
            }
        );
        this.AccessLayer = Polymorphic.Create(
            [],
            function() {
                return layer;
            },
            [Number],
            function(new_layer) {
                last_layer = layer;
                layer = new_layer;
                this.Invalidate();
            }
        );
        this.AccessVisibility = Polymorphic.Create(
            [],
            function() {
                return visibility;
            },
            [Boolean],
            function(new_visibility) {
                last_visibility = visibility;
                visibility = new_visibility;
                this.Invalidate();
            }
        );
        this.AccessBackgroundColor = Polymorphic.Create(
            [],
            function() {
                return bgcolor;
            },
            [String],
            function(new_bgcolor) {
                last_bgcolor = bgcolor;
                bgcolor = new_bgcolor;
                this.Invalidate();
            }
        );
        this.AccessOverflow = Polymorphic.Create(
            [],
            function() {
                return [overflow_x, overflow_y];
            },
            [String, String],
            function(new_overflow_x, new_overflow_y) {
                last_overflow_x = overflow_x;
                last_overflow_y = overflow_y;
                overflow_x = new_overflow_x;
                overflow_y = new_overflow_y;
                this.Invalidate();
            }
        );
        this.HasChild = Polymorphic.Create(
            [ns.BaseObject],
            function(child) {
                for (var idx = 0; idx < children.length; ++idx) {
                    if (children[idx] == child) {
                        return true;
                    }
                }
                return false;
            }
        );
        this.AddChild = Polymorphic.Create(
            [ns.BaseObject],
            function(child) {
                //  Check duplication.
                if (this.HasChild(child)) {
                    throw "Duplicated child.";
                }

                //  Check the parent.
                if (child.IsOnDocument()) {
                    throw "Already on document.";
                }

                //  Add the child to the children list.
                children.push(child);

                //  Set the parent of the child.
                child.AccessParent(this);

                //  Render the child to the DOM.
                element.append($(child.GetHTMLElement()));

                //  Invalidate.
                invalidate_children = true;
                this.Invalidate();
            }
        );
        this.RemoveChild = Polymorphic.Create(
            [ns.BaseObject],
            function(child) {
                for (var idx = 0; idx < children.length; ++idx) {
                    if (children[idx] == child) {
                        //  Remove the child from the children list.
                        children.splice(idx, 1);

                        //  Remove the child from the DOM.
                        $(child.GetHTMLElement()).detach();

                        //  Set the parent of the child.
                        child.AccessParent(null);

                        //  Invalidate.
                        invalidate_children = true;
                        this.Invalidate();

                        return;
                    }
                }
                throw "No such child.";
            }
        );
        this.QueryChildren = Polymorphic.Create(
            [],
            function() {
                return this.QueryChildren(null);
            },
            [Function],
            function(object_type) {
                var result = [];
                children.forEach(function(child) {
                    if (object_type === null || (child instanceof object_type)) {
                        result.push(child);
                    }
                });
                return result;
            }
        );

        //  Save the "this" pointer.
        var out = this;

        //  Bind events.
        element.mousedown(function(event) {
            out.TriggerEvent("MouseDown", GetEventOffsetPosition(event));
        }).mousemove(function(event) {
            out.TriggerEvent("MouseMove", GetEventOffsetPosition(event));
        }).mouseup(function(event) {
            out.TriggerEvent("MouseUp", GetEventOffsetPosition(event));
        }).mouseleave(function(event) {
            out.TriggerEvent("MouseLeave", GetEventOffsetPosition(event));
        }).click(function(event) {
            out.TriggerEvent("Click", GetEventOffsetPosition(event));
        });

        //  Invalidate immediately after created.
        this.Invalidate();
    }

    //  Inherit "AbsoluteContainer" from "BaseContainer".
    Inherit(AbsoluteContainer, ns.BaseContainer);

    //  Export public APIs / classes.
    Namespace.Export(ns, "AbsoluteContainer", AbsoluteContainer);
});